from fastapi import APIRouter, Request, Form, Query, Depends, HTTPException
from fastapi.responses import RedirectResponse, JSONResponse
from sqlalchemy.orm import Session
from database import get_db
from models import Users, ApiCalls, ApiCallLogs, UserType
from datetime import datetime, date
import random, re
from urllib.parse import urlparse
import base64
import hashlib
import time
import json
import asyncio
from parser import parse_video_share_url, parse_video_id, VideoSource


router = APIRouter(tags=["API接口模块"], prefix="/api")

LIMITS = {"free":10, "month":2000, "season":3500, "year":8000}

def is_valid_url(url: str) -> bool:
    """
    验证URL是否有效
    检查是否包含合法协议(http/https)和域名
    """
    # 基本格式校验正则
    url_pattern = re.compile(
        r'^https?://'  # 必须以http://或https://开头
        r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|'  # 域名
        r'localhost|'  # 本地主机
        r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'  # IP地址
        r'(?::\d+)?'  # 可选端口号
        r'(?:/?|[/?]\S+)$', re.IGNORECASE)

    # 先通过正则做初步校验
    if not url_pattern.match(url):
        return False

    # 进一步解析URL检查组件
    try:
        result = urlparse(url)
        # 必须有网络位置(netloc)和协议(scheme)
        return all([result.scheme, result.netloc])
    except:
        return False

def getToken(e: str) -> str:
    """
    getToken 函数，包含 Base64 编码、加盐和 MD5 哈希计算。

    参数:
        e (str): 输入的原始字符串（如 clientId + Url + clientSecretKey）

    返回:
        str: 加盐后 MD5 哈希值（32 位十六进制字符串）
    """
    # 步骤1：Base64 编码输入字符串 e（与 JS 逻辑一致）
    # 1.1 将字符串转为 UTF-8 字节（JS 中 base64encode 通常基于 UTF-8）
    e_bytes = e.encode('utf-8')
    # 1.2 进行 Base64 编码，结果转为字符串（去除 JS 可能的填充差异）
    e_b64 = base64.b64encode(e_bytes).decode('utf-8')

    # 步骤2：定义固定盐值（与原 JS 中的 "donggansalt" 一致）
    salt = "donggansalt"

    # 步骤3：盐值与 Base64 编码结果拼接（顺序：盐值 + Base64 字符串）
    salted_e = salt + e_b64

    # 步骤4：计算最终 MD5 哈希并返回（与小程序JS 的 return md5(e) 一致）
    return hashlib.md5(salted_e.encode('utf-8')).hexdigest()

def getSign(Url: str, client_secret_key: str, timestamp: int) -> str:
    """
    生成时间戳和签名（对应原 JavaScript 中的 timestamp 和 sign 逻辑）

    参数:
        Url (str): 请求的 URL 地址
        client_secret_key (str): 客户端密钥
        timestamp: 客户端时间戳

    返回:
        str: 签名值（32 位十六进制字符串）
    """
    # 步骤1：拼接签名的原始字符串（顺序与 JS 一致：Url + timestamp + clientSecretKey）
    sign_raw = f"{Url}{timestamp}{client_secret_key}"  # 直接拼接字符串

    # 步骤2：计算 MD5 哈希（与 小程序JS 的 func.md5 一致，返回十六进制字符串）
    sign = hashlib.md5(sign_raw.encode('utf-8')).hexdigest()  # 编码为 UTF-8 字节后计算

    return sign

@router.get("/parse_v")  # 无动态参数
def parse_video(
    url: str = Query(..., description="视频URL"),
    key: str = Query(..., description="请求标识"),
    type: str = Query(..., description="请求类型"),
    clientId: str = Query(..., description="客户端ID"),
    clientSecretKey: str = Query(..., description="客户端密钥"),
    timestamp: str = Query(..., description="时间戳"),
    token: str = Query(..., description="令牌"),
    sign: str = Query(..., description="签名"),
    db: Session = Depends(get_db)
):
    # 1. 第一优先级：校验所有参数值不能为空白（空字符串或纯空格）
    # 定义需要校验的参数（参数名: 描述）
    params_to_check = {
        "url": "视频URL",
        "key": "请求标识",
        "type": "请求类型",
        "clientId": "客户端ID",
        "clientSecretKey": "客户端密钥",
        "timestamp": "时间戳",
        "token": "令牌",
        "sign": "签名"
    }

    # 逐个检查参数
    for param_name, param_desc in params_to_check.items():
        # 获取参数值（使用locals()动态获取变量值）
        param_value = locals()[param_name]
        # 检查是否为空白（空字符串或仅包含空格）
        if not param_value or not param_value.strip():
            raise HTTPException(
                status_code=301,
                detail=f"{param_desc}不能为空（参数名：{param_name}）"
            )

    # 根据业务需求确认逻辑运算符是and还是or
    if key != "applet" or type != "miniprogram":
        raise HTTPException(status_code=301, detail="非法请求 key_&_type")

    # 2. 验证URL有效性
    if not is_valid_url(url):
        raise HTTPException(status_code=301, detail="非法请求\无效的URL格式，请确保包含http://或https://")

    user = db.query(Users).filter_by(client_id=clientId, client_secret=clientSecretKey).first()
    if not user or user.status != 1:
        raise HTTPException(301, "无效的接口凭证")

    # 3. VIP状态检查逻辑
    current_time = datetime.utcnow()
    if user.vip_status != 0:
        # 若VIP有效但未设置过期时间，视为异常
        if not user.vip_expire:
            raise HTTPException(301, "VIP信息异常，请联系管理员")

        # 检查是否过期
        if current_time > user.vip_expire:
            # 更新为非VIP状态
            user.vip_status = 0
            user.user_type = "free"
            db.commit()
            raise HTTPException(301, "无法获取解析（账号授权已过期）")

    token_data = clientId + url + clientSecretKey
    token_str = getToken(token_data)
    print(token_str)
    if token != token_str:
        raise HTTPException(301, "无效的token接口凭证")

    sign_str = getSign(url, clientSecretKey, timestamp)
    print(f"Sign: {sign_str}")
    if sign != sign_str:
        raise HTTPException(301, "无效的sign接口凭证")

    if user.user_type.value == 'admin':
        limit = 100000
    else:
        limit = LIMITS.get(user.user_type.value, 10)

    today = date.today()
    record = db.query(ApiCalls).filter_by(user_id=user.user_id, call_date=today).first()
    if not record:
        record = ApiCalls(user_id=user.user_id, call_date=today, call_count=0)
        db.add(record)
    if record.call_count >= limit:
        raise HTTPException(301, "调用次数已达上限")

    video_info = parse_video_or_images(url)
    if video_info:
        record.call_count += 1
        log = ApiCallLogs(user_id=user.user_id, url=url)
        db.add(log)
        db.commit()

        return {
            "code": 200,
            "msg": "解析成功",
            "data": video_info
        }


def parse_video_or_images(url: str) -> dict:
    try:
        # 获取 VideoInfo 实例
        video_parse_info = asyncio.run(parse_video_share_url(url))

        # 提取 VideoAuthor 实例的属性（嵌套对象）
        author_info = video_parse_info.author  # 获取作者实例
        author_name = getattr(author_info, 'name', '未知作者')  # 安全获取作者名（防属性缺失）
        author_avatar = getattr(author_info, 'avatar', '')  # 安全获取作者头像

        parse_url = getattr(video_parse_info, 'video_url', '')
        if url:
            down_url = parse_url

        # 构造视频信息字典（直接访问 VideoInfo 实例的属性）
        video_info = {
            "title": getattr(video_parse_info, 'title', ''),  # 视频标题（防缺失）
            "cover": getattr(video_parse_info, 'cover_url', ''),  # 封面 URL（防缺失）
            "url": parse_url,  # 视频 URL（防缺失）
            "down": down_url,
            "bigFile": False,
            "quality": False,
            "images": getattr(video_parse_info, 'images', []),  # 图片列表（防缺失）
            "music_url": getattr(video_parse_info, 'music_url', ''),  # 音乐 URL（防缺失）
            "author": {
                "name": author_name,  # 作者名（从嵌套实例提取）
                "avatar": author_avatar  # 作者头像 URL（从嵌套实例提取）
            }
        }

        # video_info = {
        #     "title": getattr(video_parse_info, 'title', ''),  # 视频标题（防缺失）
        #     "cover": getattr(video_parse_info, 'cover_url', ''),  # 封面 URL（防缺失）
        #     "url": parse_url,  # 视频 URL（防缺失）
        #     "down": down_url,
        #     "bigFile": False,
        #     "quality": [
        #         {
        #             "level": "操作",
        #             "filesize": "直接下载",  # 注意：实际需根据接口返回调整（如从实例中获取）
        #             "url": getattr(video_parse_info, 'video_url', ''),  # 使用视频 URL
        #             "bigFile": False
        #         },
        #         {
        #             "level": "操作",
        #             "filesize": "复制链接",  # 同上（示例硬编码，需按需修改）
        #             "url": getattr(video_parse_info, 'video_url', ''),
        #             "bigFile": True
        #         }
        #     ],
        #     "images": getattr(video_parse_info, 'images', []),  # 图片列表（防缺失）
        #     "music_url": getattr(video_parse_info, 'music_url', ''),  # 音乐 URL（防缺失）
        #     "author": {
        #         "name": author_name,  # 作者名（从嵌套实例提取）
        #         "avatar": author_avatar  # 作者头像 URL（从嵌套实例提取）
        #     }
        # }

        return video_info

    except AttributeError as e:
        # 处理属性不存在的情况（如 VideoInfo 或 VideoAuthor 缺少字段）
        print(f"缺少必要属性 {str(e)}，请检查 VideoInfo 或 VideoAuthor 类定义")
    except Exception as e:
        print(f"解析失败: {str(e)}")
    return {}  # 所有异常时返回空字典（或根据需求调整）


@router.get("/parse_v/{video_id}")  # 有动态参数
def parse_video_with_id(
    video_id: str,  # 路径参数
    url: str = Query(..., description="视频URL"),
    key: str = Query(..., description="请求标识"),
    type: str = Query(..., description="请求类型"),
    client_id: str = Query(..., description="客户端ID"),
    client_secret: str = Query(..., description="客户端密钥"),
    timestamp: str = Query(..., description="时间戳"),
    token: str = Query(..., description="令牌"),
    sign: str = Query(..., description="签名"),
    db: Session = Depends(get_db)
):
    # 同样处理权限验证
    if key != "applet" and type != "miniprogram":
        raise HTTPException(status_code=301, detail="非法请求")

    # 2. 验证URL有效性
    if not is_valid_url(url):
        raise HTTPException(status_code=400, detail="非法请求\无效的URL格式，请确保包含http://或https://")

    # 处理带video_id的业务逻辑...
    return {"code": 200, "msg": "成功", "video_id": video_id}